﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Camera2DModule {

	public class Camera {

		private const float ZOOM_UPPER_LIMIT = 10.0f;
		private const float ZOOM_LOWER_LIMIT = 1f; // TODO: Allowing this to be smaller than one (pull back) seems problematic.

		private readonly int ViewportHeight;
		private readonly int ViewportWidth;
		private readonly int WorldHeight;
		private readonly int WorldWidth;
		private Vector2 position;
		private float zoom;

	    public bool IsFollowingPlayer;

		public Camera(Viewport viewport, int worldWidth, int worldHeight, float initialZoom, bool isFollowingPlayer = true) {
			ViewportWidth = viewport.Width;
			ViewportHeight = viewport.Height;
			WorldWidth = worldWidth;
			WorldHeight = worldHeight;
			zoom = initialZoom;
		    IsFollowingPlayer = isFollowingPlayer;
		}

		public float Zoom {
			get { return zoom; }
			set {
				zoom = value;
				if(zoom < ZOOM_LOWER_LIMIT) {
					zoom = ZOOM_LOWER_LIMIT;
				} else if(zoom > ZOOM_UPPER_LIMIT) {
					zoom = ZOOM_UPPER_LIMIT;
				}
			}
		}

		public Vector2 Position {
			get { return position; }
			set {
				float leftBarrier = ViewportWidth * .5f / zoom;             // todo: optimize. Only on ZOOM change.
				float rightBarrier = WorldWidth-ViewportWidth * .5f / zoom; // todo: optimize
				float topBarrier = WorldHeight-ViewportHeight * .5f / zoom; // todo: optimize
				float bottomBarrier = ViewportHeight * .5f / zoom;          // todo: optimize
				Vector2 tempPosition = value;
				if(tempPosition.X < leftBarrier) {
					tempPosition.X = leftBarrier;
				} else if(tempPosition.X > rightBarrier) {
					tempPosition.X = rightBarrier;
				}
				if(tempPosition.Y < bottomBarrier) {
					tempPosition.Y = bottomBarrier;
				} else if(tempPosition.Y > topBarrier) {
					tempPosition.Y = topBarrier;
				} 
				position = tempPosition;
			}
		}

		public void Move(Vector2 amount) {
			Position += amount;
		}

		public Matrix GetTransformation() {
			Matrix Transform = Matrix.CreateTranslation(new Vector3(-position.X, -position.Y, 0)) * // todo: add rotation back in?
						       Matrix.CreateScale(new Vector3(Zoom, Zoom, 1)) * 
						       Matrix.CreateTranslation(new Vector3(ViewportWidth * 0.5f, ViewportHeight * 0.5f, 0));
			return Transform;
		}

	}

}